package com.xinchuang.service.targetSystem.Impl.indexUtil;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xinchuang.common.KeyWordSystem;
import com.xinchuang.entity.IndexCompute.*;
import com.xinchuang.entity.target.TargetBaseData;
import com.xinchuang.entity.target.TargetSpecialAttribute;
import com.xinchuang.entity.targetSystem.target.TargetAnalyseTable;
import com.xinchuang.mapper.target.TargetBaseDataMapper;
import com.xinchuang.mapper.target.TargetSpecialAttributeMapper;
import com.xinchuang.mapper.targetSystem.MyUtilMapper;
import com.xinchuang.mapper.targetSystem.target.TargetAnalyseTableMapper;
import com.xinchuang.service.RedisUseService;
import com.xinchuang.service.targetSystem.indexUtil.IndexValueService;
import com.xinchuang.util.FileElseUtil;
import com.xinchuang.util.LngLatUtil;
import com.xinchuang.util.RedisUtil;
import com.xinchuang.utils.ObjectUtil;
import com.xinchuang.utils.RedisName;
import fr.opensagres.xdocreport.template.formatter.IFieldsMetadataClassSerializer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * TODO
 *
 * @author zkwczx
 * @version 1.0
 * @date 2024/4/18 20:00
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class IndexValueServiceImpl implements IndexValueService {

    private final MyUtilMapper my;

    private final RedisUtil redisUtil;

    private final TargetSpecialAttributeMapper targetSpecialAttributeMapper;

    private final KeyWordSystem keyWordSystem;

    private final TargetAnalyseTableMapper targetAnalyseTableMapper;

    private final TargetBaseDataMapper targetBaseDataMapper;

    @Override
    public double entryIndexValue(String msgType, String indexMsg, boolean isTarget, String targetOrSubId) {
        if (StringUtils.isBlank(msgType)) {
            return 0;
        }
        switch (msgType) {
            case "oneFieldRange":
                return oneFieldRange(indexMsg, isTarget, targetOrSubId);
            case "targetQuantity":
                return targetQuantity(indexMsg, isTarget, targetOrSubId);
            case "targetType":
                return targetType(indexMsg, isTarget, targetOrSubId);
            case "targetPosition":
                return targetPosition(indexMsg, isTarget, targetOrSubId);
            case "targetDistance":
                return targetDistance(indexMsg, isTarget, targetOrSubId);
            case "targetPositionDistance":
                return targetPositionDistance(indexMsg, isTarget, targetOrSubId);
            case "divide":
                return divide(indexMsg, isTarget, targetOrSubId);
            case "paramesScope":
                return paramesScope(indexMsg, isTarget, targetOrSubId);
            case "numberPointsNo":
                return numberPointsNo(indexMsg, isTarget, targetOrSubId);
            case "fixedScore":
                return fixedScore(indexMsg);
            case "selectValue":
                return selectValue(indexMsg, isTarget, targetOrSubId);
            case "numberPoints":
            case "haveScore":
            case "resultStatistics":
            default:
                return 0;
        }
    }

    private double oneFieldRange(String indexMsg, boolean isTarget, String targetOrSubId) {
        try {
            OneFieldRange one = JSONObject.parseObject(indexMsg, OneFieldRange.class);
            double value = getKeyValue(one.getField(), isTarget, targetOrSubId);
            if (value > 0) {
                if (CollectionUtil.isNotEmpty(one.getValueDataList())) {
                    for (OneFieldRangeValueData data : one.getValueDataList()) {
                        if (value >= data.getMinValue() && value < data.getMaxValue()) {
                            return FileElseUtil.getObjectToDouble(data.getScore());
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("oneFieldRange:" + e.getMessage(), e);
        }
        return 0;
    }

    private double targetQuantity(String indexMsg, boolean isTarget, String targetOrSubId) {
        try {
            TargetQuantity quantity = JSONObject.parseObject(indexMsg, TargetQuantity.class);
            Integer number = getSubNumberByKey(isTarget, targetOrSubId, quantity.getField(), quantity.getFiltrationfield(), quantity.getFiltrationValue());
            List<TargetQuantityValueDat> valueDataList = quantity.getValueDataList();
            if (CollectionUtil.isNotEmpty(valueDataList)) {
                for (TargetQuantityValueDat data : valueDataList) {
                    if (number >= data.getMinValue() && number < data.getMaxValue()) {
                        return FileElseUtil.getObjectToDouble(data.getScore());
                    }
                }
            }
            return 0;
        } catch (Exception e) {
            log.error("targetQuantity:" + e.getMessage(), e);
        }
        return 0;
    }

    private double targetType(String indexMsg, boolean isTarget, String targetOrSubId) {
        try {
            double value = 0D;
            TargetTypeIndex typeIndex = JSONObject.parseObject(indexMsg, TargetTypeIndex.class);
            Set<String> set = new HashSet<>();
            for (TargetTypeIndexValueData data : typeIndex.getValueDataList()) {
                if (!set.contains(data.getFieldtype())) {
                    Integer subNumber = getSubNumber(isTarget, targetOrSubId, data.getFieldtype());
                    value += FileElseUtil.getObjectToDouble(subNumber * data.getScore());
                }
                set.add(data.getFieldtype());
            }
            return value;
        } catch (Exception e) {
            log.error("targetType:" + e.getMessage(), e);
        }
        return 0;
    }

    private double targetPosition(String indexMsg, boolean isTarget, String targetOrSubId) {
        try {
            if (isTarget) {
                TargetPosition object = JSONObject.parseObject(indexMsg, TargetPosition.class);
                if (2 == object.getPositiontype()) {
                    return 0D;
                }
                List<Double> position = getPosition(object.getPositiontype(), targetOrSubId, object.getPosition());
                if (CollectionUtil.isNotEmpty(position) && CollectionUtil.isNotEmpty(object.getValueDataList())) {
                    TargetBaseData baseData = targetBaseDataMapper.selectById(targetOrSubId);
                    if (ObjectUtil.isNotEmpty(baseData)) {
                        double distance = LngLatUtil.getDistance(position.get(0), position.get(1), Double.parseDouble(baseData.getLon()), Double.parseDouble(baseData.getLat()));
                        for (TargetPositionValueDat data : object.getValueDataList()) {
                            if (distance >= data.getMinValue() && distance < data.getMaxValue()) {
                                return FileElseUtil.getObjectToDouble(data.getScore());
                            }
                        }
                    }
                }
            }

        } catch (Exception e) {
            log.error("targetType:" + e.getMessage(), e);
        }
        return 0;
    }

    private double targetDistance(String indexMsg, boolean isTarget, String targetOrSubId) {
        try {
            if (!isTarget) {
                return 0D;
            }
            TargetDistance object = JSONObject.parseObject(indexMsg, TargetDistance.class);
            List<Double> position = getPosition(object.getPositiontype(), targetOrSubId, object.getPosition());
            if (CollectionUtil.isNotEmpty(position) && CollectionUtil.isNotEmpty(object.getValueDataList())) {
                double value = 0D;
                Set<String> set = new HashSet<>();
                for (TargetDistanceValueDat data : object.getValueDataList()) {
                    if (StringUtils.isNotEmpty(data.getTargetType())) {
                        List<TargetBaseData> baseData = targetBaseDataMapper.selectList(new LambdaQueryWrapper<TargetBaseData>().eq(TargetBaseData::getType, data.getTargetType()));
                        if (CollectionUtil.isNotEmpty(baseData)) {
                            int num = 0;
                            for (TargetBaseData datum : baseData) {
                                if (LngLatUtil.getDistance(position.get(0), position.get(1), Double.parseDouble(datum.getLon()), Double.parseDouble(datum.getLat())) <= data.getDistance()) {
                                    num++;
                                }
                            }
                            if (num >= data.getMinValue() && num <= data.getMaxValue()) {
                                value += FileElseUtil.getObjectToDouble(data.getScore());
                                set.add(data.getTargetType());
                            }
                        }
                    }
                }
                return value;
            }
        } catch (Exception e) {
            log.error("targetDistance:" + e.getMessage(), e);
        }
        return 0;
    }

    private double targetPositionDistance(String indexMsg, boolean isTarget, String targetOrSubId) {
        try {
            if (isTarget) {
                TargetPositionDistance object = JSONObject.parseObject(indexMsg, TargetPositionDistance.class);
                List<Double> position = getPosition(object.getPositiontype(), targetOrSubId, object.getPosition());
                if (CollectionUtil.isNotEmpty(position) && CollectionUtil.isNotEmpty(object.getValueDataList())) {
                    double value = 0D;
                    for (TargetPositionDistanceValueDat data : object.getValueDataList()) {
                        if (StringUtils.isNotEmpty(data.getTargetType())) {
                            List<TargetBaseData> baseData = targetBaseDataMapper.selectList(new LambdaQueryWrapper<TargetBaseData>().eq(TargetBaseData::getType, data.getTargetType()));
                            if (CollectionUtil.isNotEmpty(baseData)) {
                                int num = 0;
                                for (TargetBaseData datum : baseData) {
                                    if (LngLatUtil.getDistance(position.get(0), position.get(1), Double.parseDouble(datum.getLon()), Double.parseDouble(datum.getLat())) <= data.getDistance()) {
                                        num++;
                                    }
                                }
                                value += FileElseUtil.getObjectToDouble(num * data.getScore());
                            }
                        }
                    }
                    return value;
                }
            }
        } catch (Exception e) {
            log.error("targetPositionDistance:" + e.getMessage(), e);
        }
        return 0D;
    }

    private double divide(String indexMsg, boolean isTarget, String targetOrSubId) {
        try {
            double value1 = 0;
            double value2 = 0;
            Divide divide = JSONObject.parseObject(indexMsg, Divide.class);
            if (CollectionUtil.isNotEmpty(divide.getTargetType1())) {
                value1 = getKeyValue(divide.getTargetType1(), isTarget, targetOrSubId);
            } else {
                value1 = divide.getScore1();
            }
            if (CollectionUtil.isNotEmpty(divide.getTargetType2())) {
                value2 = getKeyValue(divide.getTargetType2(), isTarget, targetOrSubId);
            } else {
                value2 = divide.getScore2();
            }
            if (value2 != 0) {
                return FileElseUtil.getObjectToDouble(value1 / value2);
            }
        } catch (Exception e) {
            log.error("divide:" + e.getMessage(), e);
        }
        return 0;
    }

    private double paramesScope(String indexMsg, boolean isTarget, String targetOrSubId) {
        try {
            ParamesScope paramesScope = JSONObject.parseObject(indexMsg, ParamesScope.class);
            double value1 = getKeyValue(paramesScope.getTargetType1(), isTarget, targetOrSubId);
            double value2 = getKeyValue(paramesScope.getTargetType1(), isTarget, targetOrSubId);
            for (ParamesScopeValueDat data : paramesScope.getValueDataList()) {
                if (value1 >= data.getMinValue1() && value1 < data.getMaxValue1()) {
                    if (value2 >= data.getMinValue2() && value2 < data.getMaxValue2()) {
                        return FileElseUtil.getObjectToDouble(data.getScore());
                    }
                }
            }
        } catch (Exception e) {
            log.error("paramesScope:" + e.getMessage(), e);
        }
        return 0;
    }

    private double numberPointsNo(String indexMsg, boolean isTarget, String targetOrSubId) {
        try {
            double finishValue = 0;
            NumberPointsNo numberPointsNo = JSONObject.parseObject(indexMsg, NumberPointsNo.class);
            Set<String> set = new HashSet<>();
            for (NumberPointsNoValueDat data : numberPointsNo.getValueDataList()) {
                if (CollectionUtil.isNotEmpty(data.getTargetType())) {
                    if (set.contains(data.getTargetType().get(1))) {
                        continue;
                    }
                    double value = getKeyValue(data.getTargetType(), isTarget, targetOrSubId);
                    finishValue += FileElseUtil.getObjectToDouble(value * data.getScore());
                    set.add(data.getTargetType().get(1));
                }
            }
            return finishValue;
        } catch (Exception e) {
            log.error("numberPointsNo:" + e.getMessage(), e);
        }
        return 0;
    }

    private double fixedScore(String indexMsg) {
        try {
            FixedScore fixedScore = JSONObject.parseObject(indexMsg, FixedScore.class);
            return FileElseUtil.getObjectToDouble(fixedScore.getValue());
        } catch (Exception e) {
            log.error("fixedScore:" + e.getMessage(), e);
        }
        return 0;
    }

    private double selectValue(String indexMsg, boolean isTarget, String targetOrSubId) {
        try {
            SelectValue selectValue = JSONObject.parseObject(indexMsg, SelectValue.class);
            return getPullValue(selectValue.getTargetType(), selectValue.getValueDataList(), isTarget, targetOrSubId);
        } catch (Exception e) {
            log.error("selectVale:" + e.getMessage(), e);
        }
        return 0;
    }

    //TODO 计算方式

    private Double getKeyValue(List<String> typeList, boolean isTarget, String targetOrSubId) {
        TargetSpecialAttribute attribute = targetSpecialAttributeMapper.selectById(typeList.get(1));
        if (ObjectUtil.isNotEmpty(attribute)) {
            Object value;
            if (isTarget && redisUtil.hHasKey(RedisName.SIGN_SUB_NAME_ALL, typeList.get(0))) {
                value = my.getSubKeyIdMaxValue(targetOrSubId, typeList.get(0), attribute.getKeyValue());
            } else {
                value = redisUtil.hget(RedisName.TARGET_SPECIAL_DATA_ALL + "_" + targetOrSubId, attribute.getKeyValue());
            }
            return FileElseUtil.getObjectToDouble(value);
        }
        return 0D;
    }

    private Integer getSubNumberByKey(boolean isTarget, String targetOrSubId, String typeId, String key, Double keyValue) {
        if (isTarget) {
            List<String> subList = my.getSubListBySubType(targetOrSubId, typeId);
            if (CollectionUtil.isNotEmpty(subList)) {
                if (StringUtils.isNotBlank(key)) {
                    TargetSpecialAttribute attribute = targetSpecialAttributeMapper.selectById(key);
                    if (ObjectUtil.isNotEmpty(attribute)) {
                        int num = 0;
                        for (String subId : subList) {
                            double aDouble = FileElseUtil.getObjectToDouble(redisUtil.hget(RedisName.TARGET_SPECIAL_DATA_ALL + "_" + subId, attribute.getKeyValue()));
                            if (aDouble >= keyValue) {
                                num++;
                            }
                        }
                        return num;
                    }
                } else {
                    return subList.size();
                }
            }
        }
        return 0;
    }

    private Integer getSubNumber(boolean isTarget, String targetOrSubId, String typeId) {
        if (isTarget) {
            List<String> subList = my.getSubListBySubType(targetOrSubId, typeId);
            if (CollectionUtil.isNotEmpty(subList)) {
                return subList.size();
            }
        }
        return 0;
    }

    private Double getPullValue(List<String> typeList, List<SelectValueValueData> valueDataList, boolean isTarget, String targetOrSubId) {
        TargetSpecialAttribute attribute = targetSpecialAttributeMapper.selectById(typeList.get(1));
        if (ObjectUtil.isNotEmpty(attribute)) {
            JSONArray array = JSONArray.parseArray(attribute.getEnumerator());
            if (CollectionUtil.isNotEmpty(array)) {
                Object value = redisUtil.hget(RedisName.TARGET_SPECIAL_DATA_ALL + "_" + targetOrSubId, attribute.getKeyValue());
                if (ObjectUtil.isNotEmpty(value)) {
                    for (SelectValueValueData valueDat : valueDataList) {
                        if (value.toString().equals(valueDat.getSelectValue())) {
                            return FileElseUtil.getObjectToDouble(valueDat.getScore());
                        }
                    }
                }
            }
        }
        return 0D;
    }

    private List<Double> getPosition(int pType, String targetOrSubId, String myP) {
        if (1 == pType) {
            TargetAnalyseTable analyseTable = targetAnalyseTableMapper.selectOne(new LambdaQueryWrapper<TargetAnalyseTable>().eq(TargetAnalyseTable::getRedId, targetOrSubId).last("LIMIT 1"));
            if (StringUtils.isNotEmpty(analyseTable.getFightPosition())) {
                JSONArray array = JSONArray.parseArray(analyseTable.getFightPosition());
                double tLon = array.getDouble(0);
                double tLat = array.getDouble(1);
                return Arrays.asList(tLon, tLat);
            }
        } else if (2 == pType) {
            Object position = redisUtil.hget(RedisName.TARGET_SPECIAL_DATA_ALL + "_" + targetOrSubId, "position");
            if (ObjectUtil.isNotEmpty(position)) {
                JSONArray array = JSONArray.parseArray(position.toString());
                double tLon = array.getDouble(0);
                double tLat = array.getDouble(1);
                return Arrays.asList(tLon, tLat);
            }
        } else if (3 == pType && StringUtils.isNotEmpty(myP)) {
            double tLon = LngLatUtil.dfm2LatLng(myP.split(",")[0], keyWordSystem.getDu(), keyWordSystem.getFen());
            double tLat = LngLatUtil.dfm2LatLng(myP.split(",")[1], keyWordSystem.getDu(), keyWordSystem.getFen());
            return Arrays.asList(tLon, tLat);
        }
        return null;
    }

}
